package core

import (
	"errors"
	"fmt"
	"io"
	"mytool/base"
	"mytool/utils"
	"net"
	"net/http"
)

const GetCloseMessage = "\r收到关闭指令,关闭发信通道!"
const WritingEndMessage = "\r通信结束,关闭发信通道!"
const ReadingEndMessage = "\r通信结束，关闭收信通道!"

func ChatWithClient(c net.Conn) {
	readEnd := make(chan bool, 1)

	// 1 处理发送操作
	go func() {
		tips := fmt.Sprintf("[To %s]:", c.RemoteAddr().String())
		for {
			select {
			case <-readEnd:
				return
			default:
				// 1.1 通过终端向客户端发送数据,不发送空白数据，如果是exit则退出会话
				msg := utils.Input(tips, false)
				if utils.IsReturnMessage(msg) {
					continue
				}
				if utils.IsContainExit(msg) {
					utils.Out(GetCloseMessage)
					c.Close()
					return
				}
				// 1.2 发送数据
				_, err := c.Write([]byte(msg))
				if err != nil {
					utils.Out(WritingEndMessage)
					c.Close()
					return
				}
			}

		}
	}()

	// 2 处理客户端信息
	for {
		// 2.1 接受客户端信息
		buffer := make([]byte, 1024)
		n, err := c.Read(buffer)
		if err != nil {
			utils.Out(ReadingEndMessage)
			c.Close()
			readEnd <- true
			break
		}
		// 2.2 输出到终端，利用\r解决屏幕显示混乱的问题
		fmt.Printf("\r[From %s]:%s", c.RemoteAddr().String(), string(buffer[:n]))
	}

}

func Listen(args []string) (err error) {
	// 参数判断
	if len(args) > 2 {
		err = errors.New("参数错误")
		return
	}

	// 地址处理
	address := ""
	if len(args) == 2 {
		address = ":" + args[1]
	}

	// 监听端口
	sock, err := net.Listen("tcp", address)
	if err != nil {
		return
	}
	defer sock.Close()
	fmt.Println(sock.Addr(), "监听成功!")

	// 循环处理客户端的请求
	for {
		conn, _ := sock.Accept()
		utils.FmtOut("收到来自:%s的会话\n", conn.RemoteAddr().String())
		go ChatWithClient(conn)
	}

}

func StartChat(c net.Conn) {
	readEnd := make(chan bool, 1)

	// 1.接收消息
	go func() {
		for {
			buffer := make([]byte, 1024)
			n, err := c.Read(buffer)
			if err != nil {
				utils.Out(ReadingEndMessage)
				c.Close()
				readEnd <- true
				break
			}
			utils.FmtOut("\r[From %s]:%s", c.RemoteAddr().String(), string(buffer[:n]))
		}

	}()

	// 2.发送消息
	for {
		select {
		case <-readEnd:
			return
		default:
			// 2.1 从console接收输入,并判断是否需要特殊处理：不发送空白数据、判断是否是退出信息
			tips := fmt.Sprintf("[To %s]:", c.RemoteAddr().String())
			msg := utils.Input(tips, false)
			if msg == "\n" || msg == "\r\n" {
				continue
			}
			if utils.IsContainExit(msg) {
				utils.Out(GetCloseMessage)
				c.Close()
				return
			}
			// 2.2 发送
			_, err := c.Write([]byte(msg))
			if err != nil {
				utils.Out(WritingEndMessage)
				c.Close()
				return
			}
		}

	}
}

func Connect2Server(args []string) (err error) {
	// 参数校验
	if len(args) != 3 {
		return errors.New("参数错误：")
	}
	address := args[1] + ":" + args[2]

	// 建立连接
	conn, err := net.Dial("tcp", address)
	if err != nil {
		return
	}
	defer conn.Close()

	// 进入会话
	utils.Out("连接成功,输入exit退出.")
	StartChat(conn)
	return nil
}

// 域名解析
func Nslookup(args []string) (err error) {
	if len(args) < 2 {
		return errors.New("参数错误")
	}
	for _, v := range args[1:] {
		addrs, err := net.LookupHost(v)
		if err != nil {
			return err
		}
		fmt.Println(v, addrs)
	}
	return nil
}

// 查询ip的地理位置
func IpLocation(args []string) (err error) {
	// 参考地址https://blog.csdn.net/mouday/article/details/113767228
	if len(args) != 2 {
		return errors.New("参数错误")
	}

	// 发起网络请求
	address := args[1]
	url := fmt.Sprintf(`https://ip.taobao.com/outGetIpInfo?ip=%s&accessKey=alibaba-inc`, address)
	response, err := http.Get(url)
	if err != nil {
		return err
	}
	defer response.Body.Close()

	// 读取响应的数据
	bytes := make([]byte, 1024)
	s := ""
	for {
		n, err := response.Body.Read(bytes)
		if n == 0 {
			break
		}
		if err != nil && err != io.EOF {
			fmt.Println(err)
			break
		}
		s += string(bytes[:n])
	}
	// json转map
	//type Data struct {
	//	country string
	//	region string
	//	city string
	//	isp string
	//}
	//
	//type Result struct {
	//	data *Data
	//}

	//m := new(Result)
	utils.Out(s)
	//err = json.Unmarshal([]byte(s), &m)
	//if err != nil {
	//	fmt.Println(err.Error())
	//	return
	//}
	//fmt.Println(m)
	//fmt.Println(address, m.data.country, m.data.region, m.data.city, m.data.isp)

	return nil
}

func NetTools() []*base.Option {
	return []*base.Option{
		&base.Option{"listen", Listen, "listen <port> 监听指定TCP端口. eg. listen 80"},
		&base.Option{"connect", Connect2Server, "connect <ip port> 测试指定TCP端口是否打开. eg. connect 192.168.1.1 80"},
		&base.Option{"systeminfo", PCInfo, "查看系统状态信息"},
		&base.Option{"nslookup", Nslookup, "nslookup [domain1 domain2 ...] 域名解析."},
		&base.Option{"ipl", IpLocation, "ipl <address> eg ipl 8.8.8.8  查询ip的地理位置与归宿地. "},
	}
}
